//! + 错误码: 0b10 用于 EFI，0b11 则用于 OEM
//! + 告警码：0b00 用于 EFI，0b01 用于 OEM

use bits::{BitsOps, IntoBits};

macro_rules! error_code {
    ($code:literal) => {
        // 最高位置 1
        $code | 1usize.rotate_right(1)
    };
}

macro_rules! warn_code {
    ($code:literal) => {
        // 最高位清 0
        $code & (usize::MAX - 1usize.rotate_right(1))
    };
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[repr(usize)]
#[non_exhaustive]
pub enum EfiStatus {
    Success = 0,
    /// 镜像加载失败
    LoadError = error_code!(1),
    /// 参数不正确
    InvalidParameter = error_code!(2),
    /// 操作不支持
    Unsupported = error_code!(3),
    /// 缓冲区大小不正确
    BadBufferSize = error_code!(4),
    /// 缓冲区太小，错误发生时，所需要要的大小会从恰当的参数中返回。
    BufferTooSmallError = error_code!(5),
    /// 还没有数据。
    NotReady = error_code!(6),
    /// 当尝试操作时，物理设备报告了一个错误。
    DeviceError = error_code!(7),
    /// 设备无法被写入。
    WriteProtected = error_code!(8),
    /// 资源已被耗尽
    OutOfResources = error_code!(9),
    /// 在文件系统上检测到不一致性，导致操作失败
    VolumeCorrupted = error_code!(10),
    /// There is no more space on the file system.
    VolumeFull = error_code!(11),
    /// The device does not contain any medium to perform the operation.
    NoMedia = error_code!(12),
    /// The medium in the device has changed since the last access.
    MediaChanged = error_code!(13),
    /// The item was not found.
    NotFound = error_code!(14),
    /// Access was denied.
    AccessDenied = error_code!(15),
    /// The server was not found or did not respond to the request.
    NoResponse = error_code!(16),
    /// A mapping to a device does not exist.
    NoMapping = error_code!(17),
    /// The timeout time expired.
    TIMEOUT = error_code!(18),
    /// The protocol has not been started.
    NotStarted = error_code!(19),
    /// The protocol has already been started.
    AlreadyStarted = error_code!(20),
    /// The operation was aborted.
    Aborted = error_code!(21),
    /// An ICMP error occurred during the network operation.
    IcmpError = error_code!(22),
    /// A TFTP error occurred during the network operation.
    TftpError = error_code!(23),
    /// A protocol error occurred during the network operation.
    ProtocolError = error_code!(24),
    /// The function encountered an internal version that was incompatible with a version requested by the caller.
    IncompatibleVersion = error_code!(25),
    /// The function was not performed due to a security violation.
    SecurityViolation = error_code!(26),
    /// A CRC error was detected.
    CrcError = error_code!(27),
    /// Beginning or end of media was reached
    EndOfMedia = error_code!(28),
    /// The end of the file was reached.
    EndOfFile = error_code!(31),
    /// The language specified was invalid.
    InvalidLanguage = error_code!(32),
    /// The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.
    CompromisedData = error_code!(33),
    /// There is an address conflict address allocation
    IpAddressConflict = error_code!(34),
    /// A HTTP error occurred during the network operation.
    HttpError = error_code!(35),
    /// The string contained one or more characters that the device could not render and were skipped.
    UnknownGlyph = warn_code!(1),
    /// The handle was closed, but the file was not deleted.
    DeleteFailure = warn_code!(2),
    /// The handle was closed, but the data to the file was not flushed properly.
    WriteFailure = warn_code!(3),
    /// The resulting buffer was too small, and the data was truncated to the buffer size.
    WarnBufferTooSmall = warn_code!(4),
    /// The data has not been updated within the timeframe set by local policy for this type of data.
    StaleData = warn_code!(5),
    /// The resulting buffer contains UEFI-compliant file system.
    FileSystem = warn_code!(6),
    /// The operation will be processed across a system reset
    ResetRequired = warn_code!(7),
}
impl EfiStatus {
    pub fn code(&self) -> usize {
        *self as usize
    }
    pub fn is_sucess(&self) -> bool {
        *self == EfiStatus::Success
    }
    pub fn is_error(&self) -> bool {
        self.code().bits(63).is_set()
    }
    pub fn is_warn(&self) -> bool {
        (self.is_sucess() == false) && (self.is_error() == false)
    }
}
